{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial 4. Immediate mode\n",
    "\n",
    "In this tutorial we will talk about a cute feature about Caffe2: immediate mode.\n",
    "\n",
    "From the previous tutorials you have seen that Caffe2 *declares* a network, and during this declaration phase, nothing gets actually executed - it's like writing the source of a program, and \"compilation/execution\" only happens later.\n",
    "\n",
    "This sometimes gets a bit tricky if we are in a researchy mind, and want to inspect typical intermediate outputs as we go. This is when the immediate mode come to help. At a high level, what the immediate mode does is to run the corresponding operators as you write them. The results live under a special workspace that can then be accessed via `FetchImmediate()` and `FeedImmediate()` runs.\n",
    "\n",
    "Let's show some examples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:root:This caffe2 python run does not have GPU support. Will run CPU only.\n",
      "WARNING:root:Debug message: No module named libcaffe2_python_gpu\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from caffe2.python import cnn, core, visualize, workspace\n",
    "import numpy as np\n",
    "import os\n",
    "core.GlobalInit(['caffe2', '--caffe2_log_level=-1'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "Now, as we have known before, in the normal mode, when you create an operator, we are *declaring* it only, and nothing gets actually executed. Let's re-confirm that."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Before execution, workspace contains X: False\n",
      "After execution, workspace contains X: True\n"
     ]
    }
   ],
   "source": [
    "workspace.ResetWorkspace()\n",
    "# declaration\n",
    "op = core.CreateOperator(\"GaussianFill\", [], \"X\", shape=[3, 5])\n",
    "print('Before execution, workspace contains X: {}'\n",
    "      .format(workspace.HasBlob(\"X\")))\n",
    "# execution\n",
    "workspace.RunOperatorOnce(op)\n",
    "print('After execution, workspace contains X: {}'\n",
    "      .format(workspace.HasBlob(\"X\")))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## Entering and exiting immediate mode.\n",
    "\n",
    "Entering immediate mode is easy: you basically invoke `workspace.StartImmediate()`. Since immediate mode has quite a lot of side effects, it would be good to read through the warning message to make sure you understand the implications.\n",
    "\n",
    "(If you don't want to see the messages, pass `i_know=True` to `StartImmediate` to suppress that.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "    Enabling immediate mode in caffe2 python is an EXTREMELY EXPERIMENTAL\n",
      "    feature and may very easily go wrong. This is because Caffe2 uses a\n",
      "    declarative way of defining operators and models, which is essentially\n",
      "    not meant to run things in an interactive way. Read the following carefully\n",
      "    to make sure that you understand the caveats.\n",
      "\n",
      "    (1) You need to make sure that the sequences of operators you create are\n",
      "    actually runnable sequentially. For example, if you create an op that takes\n",
      "    an input X, somewhere earlier you should have already created X.\n",
      "\n",
      "    (2) Caffe2 immediate uses one single workspace, so if the set of operators\n",
      "    you run are intended to be under different workspaces, they will not run.\n",
      "    To create boundaries between such use cases, you can call FinishImmediate()\n",
      "    and StartImmediate() manually to flush out everything no longer needed.\n",
      "\n",
      "    (3) Underlying objects held by the immediate mode may interfere with your\n",
      "    normal run. For example, if there is a leveldb that you opened in immediate\n",
      "    mode and did not close, your main run will fail because leveldb does not\n",
      "    support double opening. Immediate mode may also occupy a lot of memory esp.\n",
      "    on GPUs. Call FinishImmediate() as soon as possible when you no longer\n",
      "    need it.\n",
      "\n",
      "    (4) Immediate is designed to be slow. Every immediate call implicitly\n",
      "    creates a temp operator object, runs it, and destroys the operator. This\n",
      "    slow-speed run is by design to discourage abuse. For most use cases other\n",
      "    than debugging, do NOT turn on immediate mode.\n",
      "\n",
      "    (5) If there is anything FATAL happening in the underlying C++ code, the\n",
      "    immediate mode will immediately (pun intended) cause the runtime to crash.\n",
      "\n",
      "    Thus you should use immediate mode with extra care. If you still would\n",
      "    like to, have fun [https://xkcd.com/149/].\n",
      "    \n"
     ]
    }
   ],
   "source": [
    "workspace.StartImmediate()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that you have enabled immediate mode, any operators you run will simultaneously be executed in a separate immediate workspace. Note - the main workspace that you are working on is not affected. We designed the immediate workspace to be separate from the main workspace, so that nothing in the main workspace gets polluted."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Before execution, does workspace contains X? True\n",
      "But we can access it using the Immediate related functions.Here is a list of immediate blobs:\n",
      "['X']\n",
      "The content is like this:\n",
      "[[ 0.87197119  0.02245325 -0.48256612 -0.70905411  0.1288138 ]\n",
      " [-0.81278008 -0.25046423 -0.58188307  0.48693365 -0.35712072]\n",
      " [-0.03426806 -0.92325109 -0.00854768 -0.8590107   0.24451831]]\n"
     ]
    }
   ],
   "source": [
    "# declaration, and since we are in immediate mode, run it in the immediate workspace.\n",
    "op = core.CreateOperator(\"GaussianFill\", [], \"X\", shape=[3, 5])\n",
    "print('Before execution, does workspace contains X? {}'\n",
    "      .format(workspace.HasBlob(\"X\")))\n",
    "print('But we can access it using the Immediate related functions.'\n",
    "      'Here is a list of immediate blobs:')\n",
    "print(workspace.ImmediateBlobs())\n",
    "print('The content is like this:')\n",
    "print(workspace.FetchImmediate('X'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# After the immediate execution, you can invoke StopImmediate() to clean up.\n",
    "workspace.StopImmediate()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Manually feeding blobs\n",
    "\n",
    "But wait, you say - what if I want to create an operator that uses an input that is \"declared\" but not present yet? Since the immediate workspace does not have the input, we will encounter an exception:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "RuntimeError",
     "evalue": "[enforce fail at operator.cc:25] blob != nullptr. Encountered a non-existing input blob: X",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mRuntimeError\u001b[0m                              Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-6-d3c4082a3026>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mworkspace\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mStartImmediate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi_know\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mop\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcore\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mCreateOperator\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Relu\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"X\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"Y\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32m/mnt/xarfuse/uid-112042/b75fdb7a/caffe2/python/core.pyc\u001b[0m in \u001b[0;36mCreateOperator\u001b[1;34m(operator_type, inputs, outputs, name, control_input, device_option, arg, engine, **kwargs)\u001b[0m\n",
      "\u001b[1;32m/mnt/xarfuse/uid-112042/b75fdb7a/caffe2/python/workspace.pyc\u001b[0m in \u001b[0;36mRunOperatorImmediate\u001b[1;34m(op)\u001b[0m\n",
      "\u001b[1;32m/mnt/xarfuse/uid-112042/b75fdb7a/caffe2/python/workspace.pyc\u001b[0m in \u001b[0;36mRunOperatorOnce\u001b[1;34m(operator)\u001b[0m\n",
      "\u001b[1;31mRuntimeError\u001b[0m: [enforce fail at operator.cc:25] blob != nullptr. Encountered a non-existing input blob: X"
     ]
    }
   ],
   "source": [
    "workspace.StartImmediate(i_know=True)\n",
    "op = core.CreateOperator(\"Relu\", \"X\", \"Y\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "This is because immediate mode, being completely imperative, requires any input to be used to already exist in the immediate workspace. To make the immediate mode aware of such external inputs, we can manually feed blobs to the immediate workspace."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Example input is:\n",
      "[[-0.44337013 -0.31392127 -0.85655093]\n",
      " [ 0.24599633  0.69237536 -0.30405223]]\n",
      "Example output is:\n",
      "[[ 0.          0.          0.        ]\n",
      " [ 0.24599633  0.69237536  0.        ]]\n"
     ]
    }
   ],
   "source": [
    "X = np.random.randn(2, 3).astype(np.float32)\n",
    "workspace.FeedImmediate(\"X\", X)\n",
    "# Now, we can safely run CreateOperator since immediate mode knows what X looks like\n",
    "op = core.CreateOperator(\"Relu\", \"X\", \"Y\")\n",
    "print(\"Example input is:\\n{}\".format(workspace.FetchImmediate(\"X\")))\n",
    "print(\"Example output is:\\n{}\".format(workspace.FetchImmediate(\"Y\")))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "workspace.StopImmediate()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## When is immediate mode useful?\n",
    "\n",
    "You might want to use immediate mode when you are not very sure about the shape of the intermediate results, such as in a CNN where there are multiple convolution and pooling layers. Let's say that you are creating an MNIST convnet model but don't want to calculate the number of dimensions for the final FC layer. Here is what you might want to do."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Feature dimensions before FC layer: (50, 4, 4)\n",
      "Blob data has shape: (64, 1, 28, 28)\n",
      "Blob conv1 has shape: (64, 20, 24, 24)\n",
      "Blob pool1 has shape: (64, 20, 12, 12)\n",
      "Blob conv2 has shape: (64, 50, 8, 8)\n",
      "Blob pool2 has shape: (64, 50, 4, 4)\n",
      "Blob fc3 has shape: (64, 500)\n",
      "Blob pred has shape: (64, 10)\n",
      "Sample input:\n"
     ]
    },
    {
     "data": {
      "image/png": "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\ncHAw/B9vetkr2L7HRgAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fbbceb70a50>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "model = cnn.CNNModelHelper(order=\"NCHW\", name=\"mnist\")\n",
    "# Start the immediate mode.\n",
    "workspace.StartImmediate(i_know=True)\n",
    "\n",
    "data_folder = os.path.join(os.path.expanduser('~'), 'python', 'tutorial_data')\n",
    "data_uint8, label = model.TensorProtosDBInput(\n",
    "    [], [\"data_uint8\", \"label\"], batch_size=64,\n",
    "    db=os.path.join(data_folder, 'mnist/mnist-train-nchw-minidb'),\n",
    "    db_type='minidb')\n",
    "data = model.Cast(data_uint8, \"data\", to=core.DataType.FLOAT)\n",
    "data = model.Scale(data, data, scale=float(1./256))\n",
    "data = model.StopGradient(data, data)\n",
    "conv1 = model.Conv(data, 'conv1', 1, 20, 5)\n",
    "pool1 = model.MaxPool(conv1, 'pool1', kernel=2, stride=2)\n",
    "conv2 = model.Conv(pool1, 'conv2', 20, 50, 5)\n",
    "pool2 = model.MaxPool(conv2, 'pool2', kernel=2, stride=2)\n",
    "\n",
    "# What is the shape of pool2 again...?\n",
    "feature_dimensions = workspace.FetchImmediate(\"pool2\").shape[1:]\n",
    "print(\"Feature dimensions before FC layer: {}\".format(feature_dimensions))\n",
    "\n",
    "fc3 = model.FC(pool2, 'fc3', int(np.prod(feature_dimensions)), 500)\n",
    "fc3 = model.Relu(fc3, fc3)\n",
    "pred = model.FC(fc3, 'pred', 500, 10)\n",
    "softmax = model.Softmax(pred, 'softmax')\n",
    "\n",
    "# Let's see if the dimensions are all correct:\n",
    "for blob in [\"data\", \"conv1\", \"pool1\", \"conv2\", \"pool2\", \"fc3\", \"pred\"]:\n",
    "    print(\"Blob {} has shape: {}\".format(\n",
    "          blob, workspace.FetchImmediate(blob).shape))\n",
    "# Let's also visualize a sample input.\n",
    "print(\"Sample input:\")\n",
    "visualize.NCHW.ShowMultiple(workspace.FetchImmediate(\"data\"))\n",
    "workspace.StopImmediate()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remember, immediate mode is only intended to be used in debugging mode, and are only intended for you to verify things interactively. For example, in the use case above, what you want to do eventually is to remove the feature_dimensions argument and replace it with code that do not depend on immediate mode, such as hard-coding it."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Departing words\n",
    "\n",
    "Immediate mode could be a useful tool for quick iterations. But it could also easily go wrong. Make sure that you understand its purpose, and never abuse it in real product environments. The philosophy of Caffe2 is to make things very flexible and this is one example of it, but it also makes you easy to shoot yourself in the foot. Take care :)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
